#ifndef COEECATDEVICE_H
#define COEECATDEVICE_H

#include <QQueue>

#include <QVector>
#include <QDebug>

#include "domparser.h"
#include "ecatbusxml.h"

#include "GeneralDefine.h"
#include "measuretime.h"
#include "ethercaterror.h"
#include <ecrt.h>

#ifdef D_USE_VREP
#define  SIMULATION_MODE   //使用ｖｒｅｐ
#endif

#ifdef SIMULATION_MODE
#include "tcptovrep.h"
#define D_VREP_ROBOT_AXIS_6
#endif

#ifdef D_USE_XENOMAI
#include <rtdk.h>
#else
#define rt_printf printf
#endif

#define D_WRITE_SERVO_DATA_TO_FILE 0  //将算法给过来的数据写到文件
#if D_WRITE_SERVO_DATA_TO_FILE
#define D_TMP_SERVO_DATA_FILE  "./servodata.txt"
#endif


#define D_TEST_NOT_READ_ROBOT_FILE  0 //单独组件测试,不读机器人配置信息
#define D_TEST_NOT_READ_XML_FILE 0 //测试,不读厂商xml


#define D_USE_DC_SYNC  1 // 启用DC同步功能,
#define D_IF_DEBUG 0 //打印


#define ByteCast(x) ((quint8) (x) & 0x00FF)

//#define DRIVER_BIT_17  131072
//#define DRIVER_BIT_20  131072*8

#define D_IO_RW_TIME 1 //io读写间隔 1ms

// io设备最大支持io数目(预分配vector大小,读取厂家io配置文件的时候用到 ,预先初始化大小，避免内存多次拷贝)
#define D_IO_INDEX_MAX 64

/* 946684800 is the number of seconds between 1/1/1970 and 1/1/2000 */
#define VHD_TO_UNIX_EPOCH_SECONDS UINT64_C(946684800)
//2000年到现在总纳秒数
#define EC_TIMEVAL2TCNANO(TV) \
    (((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_nsec)

//925123612
//946684800

#define NSEC_PER_SEC 1000000000
#define TIME_SPACE_US 1000000

/// LS警告宏定义
#define D_WARM_RST_PFAIL (0x01)      //主电源缺相
#define D_WARM_LOW_BATT (0x02)     //电池电量不足
#define D_WARM_OV_TCMD (0x04)      //扭矩指令过大
#define D_WARM_OV_VCMD (0x08)      //速度指令过大
#define D_WARM_OV_LOAD (0X10)      //超载警告
#define D_WARM_SETUP (0x20)           //选定容量
#define D_WARM_UD_VTG (0x40)       //低电压警告
#define D_WARM_EMG (0x80)            //EMG警告

/// 对象字典定义

#define D_MAP_OBJECT_NULL_8BIT       0x0000 //三洋假字节，用于对齐
//#define D_MAP_OBJECT_NULL_8BIT       0x5FFE //假字节，用于对齐
#define D_MAP_OBJECT_CONTROL_WORD       0x6040 //控制字
#define D_MAP_OBJECT_OPERATION_MODE     0x6060 //控制模式
#define D_MAP_OBJECT_TARGET_POSITION    0x607A //目标位置
#define D_MAP_OBJECT_TARGET_TORQUE  0x6071 //目标扭矩
#define D_MAP_OBJECT_TARGET_SPEED  0x6081  //目标速度
#define D_MAP_OBJECT_VELOCITY_OFFSET    0x60B1 // 速度漂移
#define D_MAP_OBJECT_TORQUE_OFFSET      0x60B2 //写扭矩漂移
//#define D_MAP_OBJECT_ＭAX_SPEED  0x607F  //最大速度
//#define D_MAP_OBJECT_ＭAX_TORQUE_A 0x6072 //最大扭矩
#define D_MAP_OBJECT_HomeMeth           0x6098   //回零模式
#define D_MAP_OBJECT_HomeSearchSwitch   0x6099  //回零速度 01寻找回零开关速度, 02寻找Z相速度
#define D_MAP_OBJECT_HomeAcc            0x609A  //回零加速度


#define D_MAP_OBJECT_POSITION_ACTUAL    0x6064 //实际位置(编码器值)
#define D_MAP_OBJECT_TORQUE_ACTUAL      0x6077  //实际扭矩，only_read pdo
#define D_MAP_OBJECT_VELOCITY_ACTUAL    0x606C  //实际速度, only_read pdo
#define D_MAP_OBJECT_STATUS_WORD        0x6041 //状态字
#define D_MAP_OBJECT_MODES_OF_OPERATION_DISPLAY 0x6061 //控制模式显示
#define D_MAP_OBJECT_DIGITAL_INPUT      0x60FD  //数字输入
//#define D_MAP_OBJECT_DIGITAL_OUTPUT     0x60FE //数字输出


//#define D_MAP_OBJECT_ERROR_CODE_sanyo      0x1001 //错误码
#define D_MAP_OBJECT_ERROR_CODE_sanyo      0x2102 //三洋报警历史（32bit,取后8bit）
#define D_MAP_OBJECT_ERROR_CODE_603F         0x603F //错误码,三洋只能用sdo读

#define D_MAP_OBJECT_FOLLOWINGERROR_ACTUAL     0x60F4 // 实际跟随误差
//#define D_MAP_OBJECT_FOLLOWINGERROR_SET    0x6065// 设定电机跟随误差( LS no such pdo)

//end 对象字典

/// 对象字典指针偏移
struct ec_off_od{
    unsigned int offsetTargetPosSet; //写目标位置
    unsigned int offsetTargetTorqueSet; //写目标扭矩
    unsigned int offsetTargetSpeedSet;   //写目标速度
    unsigned int offsetMaxTorque;   //写最大扭矩
    unsigned int offsetMaxSpeedSet;   //写最大速度
    unsigned int offsetTorqueOffSet; //写扭矩漂移,
    unsigned int offsetSpeedOffSet; //写速度漂移,
    unsigned int offsetAmpModeSet; //写驱动的模式
    unsigned int offsetControlWorldSet; //写控制字
    unsigned int offsetHomeMethodSet; //写回零方式
    unsigned int offsetSpeedSearchSwitchSet; //写到找回零开关的速度
    unsigned int offsetSpeedSearchZeroSet; //写找Z相脉冲速度
    unsigned int offsetHomeAccSet; //写回零加速度, LS: not PDO

    unsigned int offsetNullData8bitSet;   //写 假字节

    unsigned int offsetServoStateGet; //读伺服状态
    unsigned int offsetEncoderGet; //读编码器
    unsigned int offsetSpeedGet; //读实际速度
    unsigned int offsetTorqueGet; //读实际力矩
    unsigned int offsetAmpModeGet; //读出来的驱动器模式
    unsigned int offsetFollowingErrorGet; //读跟随误差
    unsigned int offsetErrorCodeGet; //读错误码
    unsigned int offsetMotorDiGet; //读IO输入

} ;

/// io模块对象字典数据偏移（内部使用）
struct EcatIoDeviceDataOffset{
    unsigned int  byte_offset;
    unsigned int  bit_offset;
} ;

/// io数据结构（内部使用）
struct EcatIoDeviceDataOffsetList{
    QVector<EcatIoDeviceDataOffset> ioDi;
    QVector<EcatIoDeviceDataOffset> ioDo;
    QVector<EcatIoDeviceDataOffset> ioAi;
    QVector<EcatIoDeviceDataOffset> ioAo;
};
/*
typedef struct {
    int nodeId;
    QVector<bool> ioDi;
    QVector<bool> ioDo;
    QVector<float> ioAi;
    QVector<float> ioAo;
}IoDeviceData;//对外io数据结构
*/
//typedef  struct {
//    int position;//位置
//    int speed;//速度
//    int torque;//力矩
//}MotorData;

///获取单个轴伺服 状态
struct  ServoState{
    bool isServoOn;//( int nd );//伺服使能
    bool isServoQuickStop;//( int nd );//立即停止
    bool isServoPowerOn;//( int nd );//伺服主电源
    bool isServoTargetReached;//( int nd );//目标位置到达// only for csp mode
    bool isServoFllowingError;//( int nd );//跟随误差报警发生// only for csp mode
    bool isServoHoming;//( int nd );//回零中//only for home mode
    bool isServoHomingOk;//( int nd );//回零中//only for home mode
    bool isServoHomingErr;//( int nd );//回零中//only for home mode

    int position;//位置
    int speed;//速度
    int torque;//力矩
    int power;//功率
    int fllowingOffset;//实际跟随误差(计算值)

    int homeOffset;//写回零偏差

    int errorCode;//报警
    int warnCode;//警告
    QString errorString;
    QString warnString;
};



/**
 * @brief The SRobotIdAndAxit struct ,
 * 2017-1-3-xyf添加。通过站号直接获 取机器人ID和轴号
 */
struct SRobotIdAndAxit{
    int robotId;//机器人ID
    int axis;//轴号
};

/**
 * @brief The RobotData struct ///机器人所有数据，暂时没用
 */
struct RobotData{
    ///报警复位清除标志
    QVector<bool> resetRequestFlag;
    ///回零完成标志
    QVector<int> vGohomeFlag;
    ///寻找回零开关的速度
    QVector<int> homeSpeedToSwitch;
    ///寻找Z相的速度
    QVector<int> homeSpeedToZ;
    ///回零方式
    QVector<quint8> homeMethod;
    ///回零加速度
    QVector<int> homingAcc;
    ///回零时间超时
    QVector<time_t> startHomeTime,endHomeTime,diffHomeTime;
    ///回零偏移值
    QVector <int> zeroValue;
    ///旧的回零偏移值
    QVector <int> oldZeroValue;

    ///控制字
    QVector<unsigned short> ctlWord;
    ///状态字
    QVector<unsigned short> staWord;

    //   QVector<u_int8_t> motorDir; //轴的方向（CW/CCW），当值为0时为正，当值为224时为负
    ///原点偏移
    QVector<int> updateHomeOffset;
    ///编码因子
    QVector<double> encoderFactor;
    ///目标位置
    QVector<int> targetPos;
    ///编码器值
    QVector<int> encoderValue;
    ///旧的编码器的值
    QVector<int> encoderValueOld;
    ///扭矩偏移
    QVector<short> torqueOffset;
    ///目标扭矩
    QVector<short> targetTorque;
    ///扭矩实际值
    QVector<short> torqueActValue;
    ///速度实际值
    QVector<int> velocityActValue;
    ///跟随误差
    QVector<unsigned int> followingErrorData;
    ///跟随误差实际值
    QVector<unsigned int> followingErrorActualValue;
    ///模式显示
    QVector<quint8> ampModeDisp;
    ///驱动器的模式
    QVector<quint8> ampMode;
    ///驱动器上的IO输入
    QVector<unsigned int> motorDi;

    // QVector<bool> Di; ///IO模块上的Di输入
    //  QVector<bool> Do; ///IO模块上的Do输出
    /// 仿真目标位置
    QVector<float> targetPosDeg;
    /// 仿真 int axisn,编码器的值
    QVector<float> encoderValueDeg;
    ///伺服状态等数据
    QVector<ServoState> servoStateData;
    ///伺服数据指针
    //  QMap< int, QVector<ServoState*> >  servoStateMap;
};


/**
 * @brief The SERVOMOTOR_CONTROL_CMD enum ///写控制字
 */
enum SERVOMOTOR_CONTROL_CMD
{
    SHUTDOWN_CTLCMD,
    SWITCHON_CTLCMD,
    ENABLEOPERATION_CTLCMD,
    DISABLE_VOLTAGE_CTLCMD,
    QUICK_STOP_CTLCMD,
    DISABLE_OPERATION_CTLCMD,
    FAULT_RESET_CTLCMD
};

///**
// * @brief The ENUM_HOME_INTERRUPT enum ///归零步骤标志
// */
//enum ENUM_HOME_INTERRUPT
//{
//    EM_HOME_RUN,
//    EM_HOME_STOP,
//    EM_HOME_EMERGENCY_STOP
//};

/**
 * @brief The E_ServeoMode enum 伺服控制模式
 */
enum E_ServeoMode{
    E_ServoModeNoMode = 0,
    E_ServoModePp = 1,//pp
    E_ServoModePv = 3,
    E_ServoModeTq = 4,
    E_ServoModeHm = 6,//归零模式
    E_ServoModeIp = 7,
    E_ServoModeCsp = 8,//同步位置控制
    E_ServoModeCsv = 9,//同步速度控制
    E_ServoModeCst = 10,//同步扭矩控制
};

/**
 * @brief The EcatObjectConfig struct /// ethercat配置保存
 */
struct EcatObjectConfig{
    QVector<ec_pdo_entry_info_t> ec_entries;//pdo入口
    QVector<ec_pdo_info_t> ec_pdos;//pdo
    QVector<ec_sync_info_t> ec_syncs;//同步管理
};

/**
 * @brief The S_EcatDevInfo struct ///设备节点配置信息
 */
struct S_EcatDevInfo{
    EcatBusDevInfo devInfo;//节点信息
    EcatObjectConfig objConfig;//对象字典
};

/**
 * @brief The IoModuleAiAoInfo struct /// io模块的 ai ao 对象字典信息
 */
struct IoModuleAiAoInfo{
    int node;//节点
    unsigned int index;//主索引
    unsigned int subindex;//子索引
    int dir;//输入=EC_DIR_INPUT, 输出=EC_DIR_OUTPUT
};

enum E_EC_TYPE{
    EC_FAILED=-1,//初始化失败
    EC_ERR=0x0,//error_flag
    EC_INIT=0x01,
    EC_PREOP=0x02,
    EC_SAFEOP=0x04,
    EC_OP =0x08,
};

/**
 * @brief The CoeEcatDevice class  ethercat通信类
 *
 * change:
 *
 * 2016.8.15.xyf
 * 报警改为PDO-0x603F获取
 * 常用API改为所有电机型号通用接口
 * 多轴控制函数入口参数改为机器人号码(为支持多个机器人)
 * io以前为一个入口寄存器多个io，现在改为一个入口寄存器一个io
 * ethercat设备可以自由排列和多型号混合使用，仅需要改变配置文件
 *
 * 2016.9.10.xyf.大改
 * 设备信息改为总线模式
 * 接口改为支持多机器人
 * 所有电机使用相同配置(固定)
 * 驱动器仅返回错误码，由上层解析
 *
 * 2016.12.16.xyf.
 * 不同品牌伺服参数不太一样，改为读参数文件配置（未实现）
 *
 *  2016.12.31.xyf , 版本1.0.1
 * 添加vrep 3D模拟支持
 *
 * 2017.01.03.xyf, 版本1.0.2
 * 添加报警信息 messageLog 支持，
 * 添加直接通过站点获取机器人轴号和ID
 * 修改: 报警放生后 quickstop()单个机器人而不是所有机器人
 * 添加vrep模拟速率（取点位的时候跳过一定数量的点）
 *
 * 2017.01.9.xyf, 版本1.0.3
 * 添加vrep位置反馈，添加原点标定功能.
 *
 *  2017.01.11.xyf, 版本1.0.4
 * 添加设备准备就绪等待以防止程序配置不可用设备导致的崩溃。
 *
 *  2017.01.12.xyf, 版本1.0.5
 * 按伺服品牌　区分报警具体内容，（未实现）
 * 2017.01.16.xyf, 版本1.0.5
 *  仿真模式, 添加v_encoder_t，确保发送最后一个点给vrep (兼容所有版本)
 * 2017.01.17.xyf, 版本1.0.6
 * 伺服使能条件判定readyOK, 添加机器人使能判别接口 isServoOnRobot( );
 * 测试发现: 设备启动过程，出现只有一个设备，且是可用状态. 所以修改为更加可靠的判定
 *
 *  2017.01.17.xyf, 版本1.0.7
 * 线程加锁改为内部锁，减少对外接口(外部接口只留机器人的操作接口), 成员变量改为private（除了标志位）
 * 初始化失败后，配置一些数据，防止方位越界导致程序崩溃
 * 2017.01.17.xyf, 版本1.0.7  ， 添加打印当前日期+时间
 * 2017.01.17.xyf 版本1.0.8,　修改多机器人伺服on/off
 * 2017.2.28.xyf 版本1.0.8　，修改总线检测逻辑，先读文件再检测总线设备
 * 2017-4-8.xyf.版本1.0.9, 修改ethercat初始化过程禁止HMI各种操作.添加设备初始化失败后重启标志位
 * 修改初始化过程原点标定失败问题
 * 修改重新初始化不重置DC时钟偏移.
 * 2017.4.10~2017.5.5,版本1.1.0  改回旧的DC同步,打印时间等不涉及主要功能的小修改
 */
#ifdef COEECATDEVICE_LIBRARY
#include "coeecatdevice_global.h"
class  COEECATDEVICESHARED_EXPORT  CoeEcatDevice  : public DomParser
#else
class   CoeEcatDevice  : public DomParser
#endif
{
public:
    /**
     * @brief getInstance 单例化对象
     * @return
     */
    static CoeEcatDevice* getInstance();

    /**
     * @brief state  获取ethercat组件状态
     * @return  E_EC_TYPE
     */
    int state();

private:
    /**
     * @brief CoeEcatDevice　构造函数
     */
    CoeEcatDevice( );
    ~CoeEcatDevice();//析构

    friend class EthercatThread;

    MeasureTime* timeTest_1;
    MeasureTime* timeTest_2;
    MeasureTime* timeTest_3;
    MeasureTime* timeTest_4;
    MeasureTime* timeTest_5;
    MeasureTime* timeTest_6;


#ifdef SIMULATION_MODE

public:
    /**
       * @brief tcpVrep ，用于控制vrep
       */
    TcpToVrep* tcpVrep;
private:

    /**
       * @brief tcpCounter, 用于定时检测tcp连接
       */
    int tcpCounter;
    QVector<int> v_encoder_t;
    QVector<float> v_homeData;//零点标定弧度值，vrep用
#endif

private:
    /**
     * @brief escDevice　单例化对象指针
     */
    static CoeEcatDevice* escDevice;

    int get_data_false_count;
    pthread_mutex_t ecatThreadMutex;//线程互斥锁
    pthread_cond_t ecatCond;//线程同步信号
    pthread_mutexattr_t ecatAttr;

    /**
     * @brief fun_test_call  ///测试用函数( 1ms 周期调用 )，用于运行后 进行操作（调用函数等）
     */
    void  fun_test_call();

public:

    /**
     * @brief CoeEcatDevice::getEthercatDataLock 获取线程锁
     * @return
     */
    pthread_mutex_t*  getEthercatDataLock(  ){
        return &ecatThreadMutex;
    }

    /**
     * @brief getAllIo 获取指针数据的读和写时都必须加锁
     * @return
     */
    QVector<IoDeviceData>*  getAllIo(){
        return &ioDeviceData;
    }

    //未标明(-1=所有机器人)的函数，不能传递-1参数
   // pthread_mutex_unlock( &ecatThreadMutex );
    /**
     * @brief servoOnRobot   ///伺服使能(机器人所有轴) (robID=-1=所有机器人)
     * @param robID
     */
    void servoOnRobot( int robID );

    /**
     * @brief servoSwitch 伺服物理开关 按下/松开
     * @param robotId 机器人id
     * @param flag  　ｏｎ＝ｔｒｕｅ
     */
    void servoSwitch( int robotId , bool flag );

    /**
     * @brief servoOffRobot   ///关闭伺服(机器人所有轴)  (robID=-1=所有机器人)
     * @param robID
     */
    void servoOffRobot( int robID );

    /**
     * @brief quickStopRobot ///伺服立即停止(机器人所有轴)  (robID=-1=所有机器人)
     * @param robID
     */
    void quickStopRobot( int robID );

    /**
     * @brief goHomeRobot ///归零(机器人所有轴)(相对方式) , (未实现)
     * @param robID
     * @return 0=false, 1=true;
     */
    int goHomeRobot( int robID );

    /**
     * @brief setHomeOffsetRobot  ///零点设定
     * @param robID
     * @param valueList
     */
    int setHomeOffsetRobot(int robID, QVector<int>&valueList );

    /**
         * @brief setControlWordRobot 写控制字(机器人所有轴)
         * @param robID , -1=所有机器人
         * @param value 控制命令
         */
    void setControlWordRobot( int robID, int value );

    /**
     * @brief getServoDataRobot  ///获取轴的各种数据(机器人所有轴)
     * @param robID
     * @return
     */
    QVector<ServoState> getServoDataRobot( int robID );

    /**
     * @brief resetErrorRobot     ///报警复位(机器人所有轴)
     * @param robID 机器人ID
     */
    void resetErrorRobot( int robID );

    /**
     * @brief clearMessage
     * @param msg
     * @return   , 0=ok
     */
    int clearMessage( Message msg );

    /**
        * @brief setAlias  写别名
        * @param node  节点
        * @param alias 具体的别名
        */
    int setAlias( int node , unsigned short alias );

    /**
         * @brief setAliasRobotAxis 写别名
         * @param robID
         * @param axis 轴号
         * @param alias 具体的别名
         * @return
         */
    int setAliasRobotAxis( int robID, int axis, unsigned short alias );

    /**
         * @brief robotAxisToEthercatNode 获取指定轴的站号
         * @return 1 if ok
         */
    int robotAxisToEthercatNode(int robID, int axis, int &returnNode );

    /**
         * @brief isServoOnRobot   获取单个伺服 状态
         * @param robotId   id
         * Author:2017-1-17-xyf,添加单个机器人伺服ON（所有轴ON才正确）
         */
    bool isServoOnRobot( int robotId );//伺服使能

    /**
     * @brief homeParameterConfig 回零参数实时配置
     * @param robID  (-1=所有机器人)
     * @param methodList 回零方式
     * @param speedToSwitch ：到回零开关的速度
     * @param speedToZero ：到Z相脉冲的速度
     * @param accList ：回零加速度配置
     */
    void homeParameterConfig(
            int robID,
            QVector <quint8> methodList,
            QVector <int> speedToSwitch,
            QVector <int> speedToZero,
            QVector <int> accList );

    /**
     * @brief setMotorPositionRobot 写编码器的值
     * @param robID  (-1=所有机器人)
     * @param vPos 编码器的值
     */
    void setMotorPositionRobot(int robID, QVector<int> vPos);

    /**
     * @brief getMotorPositionRobot  计算后的编码（带零点偏移）
     * @param robID  (-1=所有机器人)
     * @return 编码器的值
     */
    QVector<int> getMotorPositionRobot( int robID );

    /**
     * @brief getMotorPositionRobot_real  读上来的真实编码器值 （真实编码器值）
     * @param robID  (-1=所有机器人)
     * @return 编码器的值
     */
    QVector<int> getMotorPositionRobot_real( int robID );

    /**
     * @brief setAmpModeRobot //设置驱动模式
     * @param robID  (-1=所有机器人)
     * @param mode 驱动器的模式
     */
    void setAmpModeRobot( int robID,  E_ServeoMode mode );

    /**
     * @brief addMsg  , 添加消息反馈
     * @param messageLevel
     * @param componentName
     * @param messageType
     * @param messageCode
     * @param robotId
     * @param parameter1
     * @param parameter2
     * @param parameter3
     * @param parameter4
     */
    void addMsg( int messageLevel,
                 std::string componentName,
                 std::string messageType,
                 int messageCode,
                 int robotId,
                 int parameter1 = 0,
                 int parameter2 = 0,
                 int parameter3 = 0,
                 int parameter4 = 0 );

    /**
     * @brief init  //初始化
     * @param sleeptime， 睡眠时间
     * @return  true if ok
     */
    bool init(int sleeptime_us);

    /**
     * @brief reInit 用于初始化失败后重新尝试
     */
    bool reInit();

    //end  OROCOS-COMPONENT API

    /**
         * @brief cycleStartTime 启动睡眠定时 ,详细：循环更新开始时间记录
         */
    void cycleStartTime();

public:

#ifdef SIMULATION_MODE
    /**
       * @brief pointProInterval   ,vrep模拟速率（取点位的时候跳过一定数量的点）
       */
    int  pointProInterval;
    int  pointProInterval_counter;
#endif


    /**
     * @brief isRequireReboot  要求重启
     */
     volatile bool isRequireReboot;
    /**
     * @brief readdyOk ///可读写域数据
     */
    volatile bool readdyOk;
    /**
     * @brief isInitOk  ///初始化成功标志 ok=true;
     */
    volatile bool isInitOk;
    /**
     * @brief error_flag  从站错误标志
     */
    volatile int error_flag;

    /**
     * @brief warningState  ///警告标志
     */
    volatile bool warningState;

    /**
     * @brief faultOccurred ///报警标志/故障发生
     */
    volatile bool faultOccurred;

    /**
     * @brief isMasterActived ///主站是否激活
     */
    volatile bool isMasterActived;

    /**
     * @brief robots  ///所有机器人信息 <机器人ID，信息>
     */
    QMap<int, RobotInfo> robots;

    /**
     * @brief robotIdKeys ///保存所有机器人ID
     */
    QList<int> robotIdKeys;

    /**
     * @brief robotServoOnFlag 伺服on标志位，记录多机器人  HMI 伺服控制
     * <机器人ＩＤ，伺服on状态true=on>
     */
    QMap<int, bool> robotServoOnFlag;

    /**
     * @brief cycle_ns //同步时间. ns 设定的睡眠周期
     */
    unsigned int cycle_ns;

private:

    //QMap<int, RobotData*> robotDataMap;//还没用
    int check_error_delay;//=12000;
    int error_flag_count;//=3

    //test 测试运行周期
//    int t_max_average;
//    int t_min_count;
//    qint64 t_max_count;
//    qint64 t_min_average;
//    long tmax;//test timer
//    long tmin;//test timer

    struct timespec t1,t2,t3,t4;//test timer
    bool checkTime;//test timer

    int minCount;
    int time3;
    int counter;//test timer

    int max_time  ;
    int min_time ;

    int pcout_1=0;
    int pcout_2=0;

    int pcout_3=0;
    int pcout_4=0;

    int pcout_5=0;
    int pcout_6=0;

    /**
     * @brief ecatDevs ///Ethercat总线上所有设备信息
     */
    QVector<S_EcatDevInfo > ecatDevs;

    /**
     * @brief robotDevs  ///<别名,设备信息>//(已经使用的设备,指向busDevs数据)
     */
    QMultiMap<int, S_EcatDevInfo* > robotDevs;

    /**
     * @brief aliasMapNode ///<别名，总线节点>(总线所有设备)
     */
    QMultiMap<int, int> aliasMapNode;

    /**
     * @brief nodeMapAlias  ///<总线节点,别名>(总线所有设备)
     */
    QMap<int, int> nodeMapAlias;

    /**
     * @brief aliasMapDeviceType ///<别名，设备类型>(总线所有设备) ,只有正常初始化完毕才能使用
     */
    QMap<int,int> aliasMapDeviceType;

    /**
     * @brief ioDeviceData     ///IO数据
     */
    QVector<IoDeviceData> ioDeviceData;

    /**
      * @brief ioDeviceDataMap  /// 指向 etherfcat 数据的指针map
      */
     QMap<int, IoDeviceData*>  ioDeviceDataMap;

    /**
     * @brief ioDevAlias ///<别名>//所有io设备别名
     */
    QVector<int> ioDevAlias;

    /**
     * @brief robotUseAliasList ///<别名>//已经使用的设备 的别名
     */
    QVector<int> robotUseAliasList;

    /**
     * @brief errorCode  ///错误码
     */
    QVector<quint8> errorCode;

    /**
     * @brief servoStateData ///伺服状态等数据
     */
    QVector<ServoState> servoStateData;

    /**
     * @brief servoStateMap  ///伺服数据指针
     */
   QMap< int, QVector<ServoState*> >  servoStateMap;

   /**
    * @brief nodeToRobotIdAndAxit  通过站号直接获取机器人ID和轴号
    * //2017-1-3-xyf添加 添加。
    */
   QVector<SRobotIdAndAxit>  nodeToRobotIdAndAxit;

//    /**
//     * @brief busXml //ethercat总线指针
//     */
//    EcatBusXml* busXml;

    /**
     * @brief master ///主站master
     */
    ec_master_t *master;

    /**
     * @brief domain ///一个结构体域的指针
     */
    ec_domain_t *domain;

    /**
     * @brief domain_p ///域数据的指针
     */
    quint8 *domain_p;

    /**
     * @brief domainOffKeep  ///域的偏移记录   bit
     */
    uint domainOffKeep;

    /**
     * @brief offCntKeep ///偏移数记录
     */
    uint offCntKeep;

    /**
     * @brief entriesCount ///对象字典总数
     */
    int entriesCount;

    /**
     * @brief motorCount ///电机总数
     */
    int motorCount;

    /**
     * @brief diCount ///DI总数
     */
    int diCount;

    /**
     * @brief doCount ///DO总数
     */
    int doCount;

    /**
     * @brief aiCount   ///DI总数
     */
    int aiCount;

    /**
     * @brief aoCount  ///DO总数
     */
    int aoCount;

    /**
         * @brief builddomainRegs 注册每个对象字典需要de信息, size > entriesCount
         *     //must be lager thean entriesCount
         */
    QVector<ec_pdo_entry_reg_t> builddomainRegs;

    /**
     * @brief ecOffOd //伺服电机模块对象字典偏移位置
     */
    QVector<ec_off_od> ecOffOd;

    /**
     * @brief ioDeviceDataOffsetMap //<别名，数据偏移>
     */
    QMap< int,  EcatIoDeviceDataOffsetList* > ioDeviceDataOffsetMap;

    /**
     * @brief ioDataOffsetList //不要直接调用，使用 ioDeviceDataOffsetMap 调用
     */
    QVector<EcatIoDeviceDataOffsetList> ioDataOffsetList;

    /**
     * @brief AiAoObjectInfo //( 为了兼容非标 设备, 使用xml的 entry 的 name 属性获取 )
     * //AI AO的对象字典
     */
    QVector<IoModuleAiAoInfo> AiAoObjectInfo;

    /**
     * @brief pHomeOffsetSdoRequest //sdo请求
     */
    QVector<ec_sdo_request_t *> pHomeOffsetSdoRequest;

    /**
     * @brief pAliasSetRegRequest //别名寄存器空间请求
     */
    QVector<ec_reg_request_t *> pAliasSetRegRequest;

    QVector<ec_sdo_request_t *> sdo_request_603f;
    QVector<ec_sdo_request_t *> sdo_request_alias;
    QVector<ec_slave_config_t *> slave_sc;

    /**
     * @brief master_state //主站的状态
     */
    ec_master_state_t master_state;

    /**
     * @brief domain_state  //域的状态
     */
    ec_domain_state_t domain_state;

    /**
     * @brief wakeupTime //唤醒时间
     */
    struct timespec wakeupTime;

    /**
     * @brief cycle_counter  //循环计数
     */
    int cycle_counter;

    /**
     * @brief sync_ref_counter //同步参考计数
     */
    unsigned int sync_ref_counter;

    /**
     * @brief sdoError ///sdo初始化错误
     */
    int sdoError;

    /**
     * @brief aliasMatchError ///别名不匹配
     */
    int aliasMatchError;

    /**
     * @brief etherCatCommError  ///通信错误
     */
    int etherCatCommError;

    /**
     * @brief slaveConfigError ///初始化配置失败
     */
    int slaveConfigError;

    /**
     * @brief domainStateRrror ///域数据读写失败， 0=ok, 网线拔了也会报这个错误
     */
    int domainStateRrror;

    /**
     * @brief domain_working_counter // 数据没被从站读取计数
     */
    int   slave_not_read_counter;

    /**
     * @brief resetRequestCnt /// 清零标志
     */
    int resetRequestCnt;

    /**
     * @brief resetRequestFlag  ///报警复位清除标志
     */
    QVector<bool> resetRequestFlag;

    /**
     * @brief vGohomeFlag  ///回零标志 0=取消，1＝执行，2＝回零中
     */
    QVector<int> vGohomeFlag;
    /**
     * @brief vGohomeFlag  ///回零完成标志　0＝没回零，１＝ｏｋ，2＝回零中
     */
    QVector<int> vHomeOkFlag;

    /**
     * @brief homeSpeedToSwitch  ///寻找回零开关的速度
     */
    QVector<int> homeSpeedToSwitch;

    /**
     * @brief homeSpeedToZ  ///寻找Z相的速度
     */
    QVector<int> homeSpeedToZ;

    /**
     * @brief homeMethod ///回零方式
     */
    QVector<quint8> homeMethod;

    /**
     * @brief homingAcc ///回零加速度
     */
    QVector<int> homingAcc;

    /**
     * @brief startHomeTime   ///回零时间超时
     */
    QVector<time_t> startHomeTime,endHomeTime,diffHomeTime;

    /**
     * @brief zeroValue ///回零偏移值
     */
    QVector <int> zeroValue;

    /**
     * @brief oldZeroValue  ///旧的回零偏移值
     */
    QVector <int> oldZeroValue;

    /**
     * @brief ctlWord ///控制字
     */
    QVector<unsigned short> ctlWord;

    /**
     * @brief staWord ///状态字
     */
    QVector<unsigned short> staWord;

    //   QVector<u_int8_t> motorDir; //轴的方向（CW/CCW），当值为0时为正，当值为224时为负

    /**
     * @brief targetPos ///写目标位置（写编码器值）
     */
    QVector<int> targetPos;

    /**
     * @brief updateHomeOffset ///原点偏移
     */
    QVector<int> updateHomeOffset;
    /**
     * @brief updateHomeOffset ///原点偏移 缓存
     */
    QMap<int, QVector<int> > tmp_updateHomeOffset;//缓存

    /**
     * @brief encoderFactor  ///编码因子
     */
    QVector<double> encoderFactor;

    /**
     * @brief encoderValue /// 计算后的的编码器值
     */
    QVector<int> encoderValue;

    /**
     * @brief encoderValueOld  ///旧的编码器的值
     */
    QVector<int> encoderValueOld;

    /**
     * @brief realEncoderValue ///读出来的编码器值（真实编码器值）
     */
    QVector<int> realEncoderValue;

    /**
     * @brief torqueOffset ///扭矩偏移
     */
    QVector<short> torqueOffset;

    /**
     * @brief targetTorque  ///目标扭矩
     */
    QVector<short> targetTorque;

    /**
     * @brief torqueActValue  ///扭矩实际值
     */
    QVector<short> torqueActValue;

    /**
     * @brief maxSpeed ///最大速度
     */
    QVector<int> maxSpeed;

    /**
     * @brief targetSpeed  ///目标速度
     */
    QVector<int> targetSpeed;

    /**
     * @brief velocityActValue ///实际速度
     */
    QVector<int> velocityActValue;

    /**
     * @brief followingErrorData ///跟随误差
     */
    QVector<unsigned int> followingErrorData;

    /**
     * @brief followingErrorActualValue ///跟随误差实际值
     */
    QVector<unsigned int> followingErrorActualValue;

    /**
     * @brief ampModeDisp  ///模式显示
     */
    QVector<quint8> ampModeDisp;

    /**
     * @brief ampMode ///驱动器的模式
     */
    QVector<quint8> ampMode;

    /**
     * @brief motorDi  ///驱动器上的IO输入
     */
    QVector<unsigned int> motorDi;

    /**
     * @brief targetPosDeg  /// 仿真目标位置
     */
    QVector<float> targetPosDeg;

    /**
     * @brief encoderValueDeg  /// 仿真 int axisn,编码器的值
     */
    QVector<float> encoderValueDeg;

    /**
       * @brief sc_ref 参考从站
       */
    ec_slave_config_t *sc_ref ;
    QVector<bool >isOp;
    //bool isOp[ 100 ];//={false};

private:


    /**
     * @brief displayEthercatConfig //打印从站配置
     * @param nd
     */
    void displayEthercatConfig( int nd );

    /**
     * @brief displayDomainRegConfig //打印域数据寄存器信息
     */
    void displayDomainRegConfig( );

    /**
     * @brief displayBusDevicesInfo //打印总线设备信息
     */
    void displayBusDevicesInfo();

    /**
     * @brief checkEcatConfigErr //检查从站配置错误（仅OP模式下有效）
     * @return
     */
    bool checkEcatConfigErr();

    /**
         * @brief servoOnNode  对单个伺服操作  //伺服使能
         * @param node  节点
         * Author:2016.9.1.xyf
         */
    void servoOnNode( int node );

    /**
     * @brief servoOffNode  //伺服去使能
     * @param node
     */
    void servoOffNode( int node );

    /**
     * @brief servoHalt 暂停运动（减速停止）
     * @param node
     */
    void servoHalt( int node );

    /**
     * @brief servoReRun //继续运动
     * @param node
     */
    void servoReRun( int node );

    /**
     * @brief servoQuickStop //立即停止
     * @param node
     */
    void servoQuickStop( int node );

    /**
         * @brief isServoOnNode   获取单个伺服 状态
         * @param nd   节点
         * Author:2016.9.1.xyf
         */
    bool isServoOnNode( int nd );//伺服使能

    /**
     * @brief isServoQuickStop //立即停止ON?
     * @param nd
     * @return
     */
    bool isServoQuickStop( int nd );

    /**
     * @brief isServoPowerOn //伺服主电源ON?
     * @param nd
     * @return
     */
    bool isServoPowerOn( int nd );

    /**
     * @brief isServoTargetReached //目标位置到达? // only for csp mode
     * @param nd
     * @return
     */
    bool isServoTargetReached( int nd );

    /**
     * @brief isServoFllowingError //跟随误差报警发生? // only for csp mode
     * @param nd
     * @return
     */
    bool isServoFllowingError( int nd );

    /**
     * @brief isServoHoming //回零中? //only for home mode
     * @param nd
     * @return
     */
    bool isServoHoming( int nd );

    /**
     * @brief isServoHomingOk //回零ok? //only for home mode
     * @param nd
     * @return
     */
    bool isServoHomingOk( int nd );

    /**
     * @brief isServoHomingErr //回零出错？ //only for home mode
     * @param nd
     * @return
     */
    bool isServoHomingErr( int nd );

    /** Update the master time based on ref slaves time diff  将主站时钟更新到从站参考时钟
    *
    * called after the ethercat frame is sent to avoid time jitter in 发送帧数据后立刻调用避免时间抖动
    * sync_distributed_clocks()
    */
    void update_master_clock(void);

    /** Synchronise the distributed clocks 分布式时钟同步
    */
    void sync_distributed_clocks(void);

    /** Convert system time to RTAI time in counts (via the system_time_base).
    * 将系统时间RTAI时间计数（通过system_time_base）。
    */
    quint64 system2count(   uint64_t time  );

    /** Get the time in ns for the current cpu, adjusted by system_time_base.
     *
     * \attention Rather than calling rt_get_time_ns() directly, all application
     * time calls should use this method instead.
     *
     * \ret The time in ns.
     *得到 当前CPU的纳秒时间，调整system_time_base。
    *
    * 注：所有的应用程序时间 应使用此方法代替， 而不是直接调用rt_get_time_ns()，
    *
    *   纳秒的 参考时间。
     */
    uint64_t system_time_ns(void);

    /**
     * @brief detectionEcatBusDevs //检测Ethercat 总线上的所有设备(获取基本信息)
     * @return
     */
    bool detectionEcatBusDevs();

    /**
     * @brief readRobotsConfig //读取机器人信息(个数和使用的ethercat配置文件)
     * @return
     */
    bool readRobotsConfig();

    /**
     * @brief readEcatBusDevsConfig //读取已经使用设备的ethercat配置信息
     * @return
     */
    bool readEcatBusDevsConfig();

    /**
     * @brief getEcatDeviceConfig //获取从站配置,(仅io模块)
     * @param node
     * @return
     */
    int getEcatDeviceConfig(int node);

    /**
     * @brief readEcatDevSettingsXml, 从厂商配置文件读取配置信息(读取sync,pdo,entry等)
     * @param xmlfile  , xml文件 路径+名字
     * @param nd ,  设备节点
     * @return 　,true if ok
     */
    bool readEcatDevSettingsXml(QString xmlfile,      int nd);

    /**
     * @brief resetDeviceType //设备检测标识
     */
    void resetDeviceType();

    /**
     * @brief resizeAllVector //根据读取到的配置信息, 设置容器大小
     */
    void resizeAllVector();

    /**
     * @brief checkAlias
    //别名检测(判断是否插错网线，识别设备是否正确)
     * @return
     */
    bool checkAlias();

    /**
     * @brief initDevice  //初始化设备(写配置 pdo ,sdo ,reg等)
     * @return
     */
    bool initDevice();

    /**
     * @brief activeMaster  //激活主站,调用后需要等待一小段时间（1ms以上），才能收发数据，不然会导致死机。
     * @return
     */
    bool activeMaster();

    /**
     * @brief syncsConfig //SM同步配置
     * @param sc
     * @param nd
     */
    void syncsConfig(ec_slave_config_t *&sc, int nd);

    /**
     * @brief entriesConfig //配置对象字典寄存器
     * @param nd
     */
    void entriesConfig(int nd);

    /**
     * @brief sdosConfig //sdo注册 (每个厂商的sdo定义是不一样的)
     * @param nd
     */
    void sdosConfig(int nd);

    /**
     * @brief customErrorSearch  //新增错误报警
     * @return
     */
    bool customErrorSearch( );

    /**
     * @brief warningSearch  //警告检测
     * @param robID
     */
    void warningSearch( int robID );

    /**
     * @brief alarmSearch //报警检测
     * @param robID
     */
    void alarmSearch( int robID );

    /**
      * @brief isAiAo 检查对象字典是否属于AI 或AO
      * @param node 节点
      * @param index 主索引
      * @param subindex 子索引
      * @return
      */
    bool isAiAo( int node, unsigned int index , unsigned int subindex );


    /**
        * Date:2016-2-23
        * Author:Tom
        * function:字节转短整形数
        * detailed:1、入口参数：b字节
        *     2、出口参数：无
        *     3、返回值：短整形数
        *     4、详细：无操作
        * Editor:
        * Why:
       */
    unsigned short bytes_to_uint16( quint8 *b );

    /**
        * Date:2016-1-23
        * Author:Tom
        * function:整数转成缓存
        * detailed:1，入口参数：无
        *     2，返回值：无
        *     3，详细：把32位的整数转换成byte型数组
        * Editor:
        * Why:
        */
    void uint32_to_bytes(unsigned int i, quint8 *b);

    /**
        * Date:2016-1-23
        * Author:Tom
        * function:短整数转成缓存
        * detailed:1，入口参数：无
        *     2，返回值：无
        *     3，详细：把16位的整数转换成byte型数组
        * Editor:
        * Why:
        */
    void uint16_to_bytes(unsigned short i, quint8 *b);

    /**
        * @brief getResultFromSystemCall  获取控制台命令返回
        * @param pCmd  写入控制台命令
        * @param pResult 返回数据
        * @param size  读取返回长度charbm5mZiIscXE
        * @return
        */
    int getResultFromSystemCall(const char* pCmd, char* pResult, int size);
    /*
     * 根据文档，process->execute("iwconfig|grep IEEE|awk '{print $1}'");
会被进一步处理为：
    QStringList gemfield;
    gemfield<<"IEEE|awk"<<"'{print $1}'";
    process->start("iwconfig|grep",gemfield);
    */

    /**
        * @brief regRealtimeRead   实时读寄存器数据
        * @param pRegRequest
        * @param pos
        * @param v
        * @param byteNum
        * @param regadr
        * @return
        */
    bool regRealtimeRead( ec_reg_request_t *pRegRequest, int pos, void *val , int byteNum, int regadr );

    /**
        * @brief regRealtimeWrite  实时写寄存器数据
        * @param pRegRequest
        * @param pos
        * @param v
        * @param byteNum
        * @param regadr
        * @return
        */
    bool regRealtimeWrite( ec_reg_request_t *pRegRequest, int pos, void *val , int byteNum, int regadr );

    /**
         * @brief sdoRealtimeRead SDO方式读取数据
         * @param pSdoRequest SDO资源申请的指针
         * @param pos 节点
         * @param v 读到的值
         * @param byteNum 读几个字节的数
         * @param offset
         * @return true if ok
         */
    bool sdoRealtimeRead( ec_sdo_request_t *pSdoRequest,
                          int pos, void *val , int byteNum, int offset );

    /**
        * @brief sdoRealtimeWrite     函数功能：在实时运行时进行SDO的数据获取
        * @param pSdoRequest       pSdoRequest:SDO请求指针
        * @param pos     pos:节点位置
        * @param v       出口参数:v:获取的数值
        * @param byteNum      byteNum:请求读取的字节数
        * @param offset       offset:获取数据的偏移
        * @return        返回值： 判断是否获取成功
        */
    bool sdoRealtimeWrite( ec_sdo_request_t *pSdoRequest, int pos, int v, int byteNum, int offset );

    /**
         * @brief updateDomainData //更新域数据 ,详细：把映射的域的要写的数据从上层获取，要读的数据返回给应用层
         */
    void updateDomainData();


    //  0x607c, HomeOffset,  pdo: LS支持Pdo，SX不支持
    /**
        * @brief sdoHomeOffsetRequest    函数功能：SDO资源申请 0x607c,HomeOffset,  LS支持Pdo，SX不支持,
        * @param sc    入口参数：sc:配置指针
        * @param node  node:节点位置
        * @return      返回值： 判断是否获取成功
        */
    bool sdoHomeOffsetRequest(ec_slave_config_t *sc, int node);

    /**
         * @brief errUpdate,   检查机器人所有轴是否有报警
         * @param robID,  机器人ID, -1=所有机器人
         */
    void errUpdate(int robID);

    /**
         * @brief errUpdateNode, 更新指定轴的报警
         * @param node, 节点位置
         */
    void errUpdateNode(int node);

    //==================

    /**
     * @brief setServoData   //写数据到伺服
     * @param robID
     */
    void setServoDataRobot(int robID);

    /**
         * @brief getServoStateData //更新数据到每个servoState结构体,
         * @param robID
         */
    void getServoStateDataRobot(int robID);
    /**
         * @brief getServoStateData //更新数据到每个servoState结构体, getServoStateDataRobot()内部调用
         * @param robID
         */
    void getServoStateData(int robID);

    /**
     * @brief setServoData   //写数据到伺服 setServoDataRobot()内部调用
     * @param robID
     */
    void setServoData(int robID);

    //================
    /**
     * @brief getMotorPositionNode //获取编码器的值
     * @param node
     * @return
     */
    int getMotorPositionNode( int node );


    /**
     * @brief goHomeNode //回零操作 (单个站点)(相对方式),只能在非ethercat线程执行,不然会卡死ethercat线程。
     * @param nd
     * @return
     * change:2017-1-12-xyf. 不用堵塞函数，此函数只写标志位和控制字，
     * 回零改为在周期函数直接通过控制字写操作，状态字检测。（未实现）
     * 需要堵塞的, 调用者自己在外部写逻辑实现，通过 servoState 读取状态.
     */
    int goHomeNode(int nd );

    /**
     * @brief resetErrorNode  //报警复位 (单个站点)
     * @param node
     * @return
     */
    bool resetErrorNode( int node );

    /**
     * @brief servoStateControlNode //写控制字 (单个站点)
     * @param node
     * @param ctlCmd
     */
    void servoStateControlNode(int node, int ctlCmd);

    /**
         * @brief rt_check_master_state,检查主站状态
         */
    int rt_check_master_state();
    int rt_check_slaves_state();

    /**
         * @brief rt_check_domain_state  :检查数据域状态
         * @return   ，返回值：0=ok
         */
    int rt_check_domain_state();

    /**
         * @brief waitNodeReadyOk, 等待数据域状态好信号,
         * 详细：等待节点就绪，判断标志是wc_state，当它等于2的时候表示所有 node都可以正常通讯
         */
    void waitNodeReadyOk();

    /**
         * @brief funSetRobotValue 写数据  （valBuff[ nd ] =  valNew[ i++ ] ）
         * @param robID
         * @param valBuff 数据buff
         * @param valNew 数据
         */
    template <typename T>
    void funSetRobotValue(int robID,
                          QVector<T> &valBuff ,
                          const QVector<T> &valNew );

    /**
     *  写数据  （valBuff[ nd ] =  valNew ）
     */
    template <typename T>
    void funSetRobotValue(int robID,
                          QVector<T> &valBuff ,
                          int valNew );
    /**
     *重置数值，注意：主要为了置位单个机器人数据（valBuff[ nd ] = valNew[ nd ] ）
     */
    template <typename T>
    void funReSetRobotValue(int robID,
                            QVector<T> &valBuff ,
                            const QVector<T> &valNew );

    /**
         * @brief funGetRobotValue 读数据
         * @param robID
         * @param valBuff  数据buff
         * @return QVector<T>
         */
    template <typename T>
    QVector<T> funGetRobotValue(int robID, const QVector<T> &valBuff );

    /**
         * @brief regAliasSetRequestRealtime reg资源申请
         * @param sc   从站配置指针
         * @param node 节点
         * @return  true表示申请成功，false表示申请失败
         */
    bool regAliasSetRequestRealtime( ec_slave_config_t *sc, int node );

    /**
         * @brief ecatUpdate  PDO数据.详细：根据模式选择运行模式，是仿真还是真实运行，先接收上次的数据，反馈给
        *     上层，然后再接收上层的数据，写入到驱动器的对象字典里面去
         */
    void ecatUpdate();
    void vrep_update();
    void igh_update();

    /**
         * @brief cycleIntervalTime   DC 睡眠定时
         * 详细：//睡眠至 唤醒时间，并设定下次唤醒时间
         * change: 2016-12-16.  使用DC
         */
    void cycleIntervalTime();

    /**
     * @brief testTimer 打印周期时间
     */
    void testTimer();
    void getNowTime();

    /**
     * @brief resetMotorPositionRobot 给具体某个驱动器的编码器复位(写最近一次记录的值)
     * @param robID (-1=所有机器人)
     */
    void resetMotorPositionRobot(int robID);

};


#endif // COEECATDEVICE_H

